home *** CD-ROM | disk | FTP | other *** search
/ Acorn RISC PD-CD 1 / Acorn RISC PD-CD 1.iso / languages / gawk / c / node < prev    next >
Encoding:
Text File  |  1990-02-20  |  6.1 KB  |  342 lines

  1. /*
  2.  * node.c -- routines for node management
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. /*
  29.  * We can't dereference a variable until after we've given it its new value.
  30.  * This variable points to the value we have to free up 
  31.  */
  32. NODE *deref;
  33.  
  34. AWKNUM
  35. r_force_number(n)
  36. NODE *n;
  37. {
  38.     char *ptr;
  39.  
  40. #ifdef DEBUG
  41.     if (n == NULL)
  42.         cant_happen();
  43.     if (n->type != Node_val)
  44.         cant_happen();
  45.     if(n->flags == 0)
  46.         cant_happen();
  47.     if (n->flags & NUM)
  48.         return n->numbr;
  49. #endif
  50.     if (n->stlen == 0)
  51.         n->numbr = 0.0;
  52.     else if (n->stlen == 1) {
  53.         if (isdigit(n->stptr[0])) {
  54.             n->numbr = n->stptr[0] - '0';
  55.             n->flags |= NUMERIC;
  56.         } else
  57.             n->numbr = 0.0;
  58.     } else {
  59.         errno = 0;
  60.         n->numbr = (AWKNUM) strtod(n->stptr, &ptr);
  61.         /* the following >= should be ==, but for SunOS 3.5 strtod() */
  62.         if (errno == 0 && ptr >= n->stptr + n->stlen)
  63.             n->flags |= NUMERIC;
  64.     }
  65.     n->flags |= NUM;
  66.     return n->numbr;
  67. }
  68.  
  69. /*
  70.  * the following lookup table is used as an optimization in force_string
  71.  * (more complicated) variations on this theme didn't seem to pay off, but 
  72.  * systematic testing might be in order at some point
  73.  */
  74. static char *values[] = {
  75.     "0",
  76.     "1",
  77.     "2",
  78.     "3",
  79.     "4",
  80.     "5",
  81.     "6",
  82.     "7",
  83.     "8",
  84.     "9",
  85. };
  86. #define    NVAL    (sizeof(values)/sizeof(values[0]))
  87.  
  88. NODE *
  89. r_force_string(s)
  90. NODE *s;
  91. {
  92.     char buf[128];
  93.     char *fmt;
  94.     long num;
  95.     char *sp = buf;
  96.  
  97. #ifdef DEBUG
  98.     if (s == NULL)
  99.         cant_happen();
  100.     if (s->type != Node_val)
  101.         cant_happen();
  102.     if (s->flags & STR)
  103.         return s;
  104.     if (!(s->flags & NUM))
  105.         cant_happen();
  106.     if (s->stref != 0)
  107.         cant_happen();
  108. #endif
  109.     s->flags |= STR;
  110.     /* should check validity of user supplied OFMT */
  111.     fmt = OFMT_node->var_value->stptr;
  112.     if ((num = (long)s->numbr) == s->numbr) {
  113.         /* integral value */
  114.         if (num < NVAL && num >= 0) {
  115.             sp = values[num];
  116.             s->stlen = 1;
  117.         } else {
  118.             (void) sprintf(sp, "%ld", num);
  119.             s->stlen = strlen(sp);
  120.         }
  121.     } else {
  122.         (void) sprintf(sp, fmt, s->numbr);
  123.         s->stlen = strlen(sp);
  124.     }
  125.     s->stref = 1;
  126.     emalloc(s->stptr, char *, s->stlen + 1, "force_string");
  127.     memcpy(s->stptr, sp, s->stlen+1);
  128.     return s;
  129. }
  130.  
  131. /*
  132.  * Duplicate a node.  (For strings, "duplicate" means crank up the
  133.  * reference count.)
  134.  */
  135. NODE *
  136. dupnode(n)
  137. NODE *n;
  138. {
  139.     register NODE *r;
  140.  
  141.     if (n->flags & TEMP) {
  142.         n->flags &= ~TEMP;
  143.         n->flags |= MALLOC;
  144.         return n;
  145.     }
  146.     if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
  147.         if (n->stref < 255)
  148.             n->stref++;
  149.         return n;
  150.     }
  151.     r = newnode(Node_illegal);
  152.     *r = *n;
  153.     r->flags &= ~(PERM|TEMP);
  154.     r->flags |= MALLOC;
  155.     if (n->type == Node_val && (n->flags & STR)) {
  156.         r->stref = 1;
  157.         emalloc(r->stptr, char *, r->stlen + 1, "dupnode");
  158.         memcpy(r->stptr, n->stptr, r->stlen+1);
  159.     }
  160.     return r;
  161. }
  162.  
  163. /* this allocates a node with defined numbr */
  164. NODE *
  165. make_number(x)
  166. AWKNUM x;
  167. {
  168.     register NODE *r;
  169.  
  170.     r = newnode(Node_val);
  171.     r->numbr = x;
  172.     r->flags |= (NUM|NUMERIC);
  173.     r->stref = 0;
  174.     return r;
  175. }
  176.  
  177. /*
  178.  * This creates temporary nodes.  They go away quite quickly, so don't use
  179.  * them for anything important 
  180.  */
  181. NODE *
  182. tmp_number(x)
  183. AWKNUM x;
  184. {
  185.     NODE *r;
  186.  
  187.     r = make_number(x);
  188.     r->flags |= TEMP;
  189.     return r;
  190. }
  191.  
  192. /*
  193.  * Make a string node.
  194.  */
  195.  
  196. NODE *
  197. make_str_node(s, len, scan)
  198. char *s;
  199. int len;
  200. int scan;
  201. {
  202.     register NODE *r;
  203.     char *pf;
  204.     register char *pt;
  205.     register int c;
  206.     register char *end;
  207.  
  208.     r = newnode(Node_val);
  209.     emalloc(r->stptr, char *, len + 1, s);
  210.     memcpy(r->stptr, s, len);
  211.     r->stptr[len] = '\0';
  212.     end = &(r->stptr[len]);
  213.            
  214.     if (scan) {    /* scan for escape sequences */
  215.         for (pf = pt = r->stptr; pf < end;) {
  216.             c = *pf++;
  217.             if (c == '\\') {
  218.                 c = parse_escape(&pf);
  219.                 if (c < 0)
  220.                     cant_happen();
  221.                 *pt++ = c;
  222.             } else
  223.                 *pt++ = c;
  224.         }
  225.         len = pt - r->stptr;
  226.         erealloc(r->stptr, char *, len + 1, "make_str_node");
  227.         r->stptr[len] = '\0';
  228.         r->flags |= PERM;
  229.     }
  230.     r->stlen = len;
  231.     r->stref = 1;
  232.     r->flags |= (STR|MALLOC);
  233.  
  234.     return r;
  235. }
  236.  
  237. /* Read the warning under tmp_number */
  238. NODE *
  239. tmp_string(s, len)
  240. char *s;
  241. int len;
  242. {
  243.     register NODE *r;
  244.  
  245.     r = make_string(s, len);
  246.     r->flags |= TEMP;
  247.     return r;
  248. }
  249.  
  250.  
  251. #define NODECHUNK    100
  252.  
  253. static NODE *nextfree = NULL;
  254.  
  255. NODE *
  256. newnode(ty)
  257. NODETYPE ty;
  258. {
  259.     NODE *it;
  260.     NODE *np;
  261.  
  262. #ifdef MPROF
  263.     emalloc(it, NODE *, sizeof(NODE), "newnode");
  264. #else
  265.     if (nextfree == NULL) {
  266.         /* get more nodes and initialize list */
  267.         emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
  268.         for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
  269.             np->nextp = np + 1;
  270.         np->nextp = NULL;
  271.     }
  272.     /* get head of freelist */
  273.     it = nextfree;
  274.     nextfree = nextfree->nextp;
  275. #endif
  276.     it->type = ty;
  277.     it->flags = MALLOC;
  278. #ifdef MEMDEBUG
  279.     fprintf(stderr, "node: new: %0x\n", it);
  280. #endif
  281.     return it;
  282. }
  283.  
  284. void
  285. freenode(it)
  286. NODE *it;
  287. {
  288. #ifdef DEBUG
  289.     NODE *nf;
  290. #endif
  291. #ifdef MEMDEBUG
  292.     fprintf(stderr, "node: free: %0x\n", it);
  293. #endif
  294. #ifdef MPROF
  295.     free((char *) it);
  296. #else
  297. #ifdef DEBUG
  298.     for (nf = nextfree; nf; nf = nf->nextp)
  299.         if (nf == it)
  300.             fatal("attempt to free free node");
  301. #endif
  302.     /* add it to head of freelist */
  303.     it->nextp = nextfree;
  304.     nextfree = it;
  305. #endif
  306. }
  307.  
  308. #ifdef DEBUG
  309. pf()
  310. {
  311.     NODE *nf = nextfree;
  312.     while (nf != NULL) {
  313.         fprintf(stderr, "%0x ", nf);
  314.         nf = nf->nextp;
  315.     }
  316. }
  317. #endif
  318.  
  319. void
  320. do_deref()
  321. {
  322.     if (deref == NULL)
  323.         return;
  324.     if (deref->flags & PERM) {
  325.         deref = 0;
  326.         return;
  327.     }
  328.     if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
  329.         deref->flags &= ~TEMP;
  330.         if (deref->flags & STR) {
  331.             if (deref->stref > 1 && deref->stref != 255) {
  332.                 deref->stref--;
  333.                 deref = 0;
  334.                 return;
  335.             }
  336.             free(deref->stptr);
  337.         }
  338.         freenode(deref);
  339.     }
  340.     deref = 0;
  341. }
  342.